//
//  SCAudioMediaPlayer.m
//  lg_zhinengbeikao_english
//
//  Created by Chao Sheng on 2021/12/20.
//  Copyright © 2021 zhukai. All rights reserved.
//

#import "SCAudioMediaPlayer.h"
#import <AVFoundation/AVFoundation.h>

@interface SCAudioMediaPlayer ()

@property (nonatomic, strong) AVPlayer *player;

@property (nonatomic, strong) AVPlayerItem *playerItem;

/// 播放速率
@property (nonatomic, assign) CGFloat rateValue;

///是否开启下载
//@property (nonatomic, assign) BOOL downloadEnable;

/// 时间观察
@property (nonatomic, strong) id timeObserve;

/// 当前时间
@property (nonatomic, assign) CGFloat currentTime;

/// 当前缓冲
@property (nonatomic, assign) CGFloat bufferTime;

/// 总时长
@property (nonatomic, assign) CGFloat totalTime;

@property (nonatomic, copy) void(^scDownloadCompletion)(NSString *downloadPath);

@end

@implementation SCAudioMediaPlayer

- (instancetype)initWithAudioURL:(NSString*)url {
    if (self = [super init]) {
        self.rateValue = 1;
        [self initPlayer:url];
    }
    return self;
}

- (instancetype)initWithAudioURL:(NSString*)url Rate:(CGFloat)rate{
    if (self = [super init]) {
        self.rateValue = rate;
        [self initPlayer:url];
    }
    return self;
}

- (instancetype)initWithRate:(CGFloat)rate {
    if (self = [super init]) {
        self.rateValue = rate;
    }
    return self;
}

- (instancetype)initWithDownloadEnable:(BOOL)download completion:(nonnull void (^)(NSString * _Nonnull))completion{
    if (self = [super init]) {
        self.rateValue = 1;
        //self.downloadEnable = download;
        self.scDownloadCompletion = completion;
    }
    return self;
}

- (void)setAudioUrl:(NSString *)audioUrl {
    _audioUrl = audioUrl;
    if (!self.playerItem) {
        [self initPlayer:audioUrl];
    }
}

#pragma mark - init
- (void)initPlayer:(NSString*)url {
    
    self.state = SCAudioMediaStateUnknow;
    self.bufferState = SCAudioMediaStateBufferUnknow;
    
    NSString *urlPath = [url stringByAddingPercentEncodingWithAllowedCharacters:[NSCharacterSet URLQueryAllowedCharacterSet]];
    NSURL *playUrl = [NSURL URLWithString:urlPath];
    
    self.playerItem = [[AVPlayerItem alloc] initWithURL:playUrl];
    //音频质量适中
    self.playerItem.audioTimePitchAlgorithm = AVAudioTimePitchAlgorithmTimeDomain;
    //支持倍速切换必须调用
    [self enableAudioTracks:YES inPlayerItem:self.playerItem];
    
    self.player = [[AVPlayer alloc] initWithPlayerItem:self.playerItem];
    if (@available(iOS 10.0, *)) {
        self.player.automaticallyWaitsToMinimizeStalling = NO;//设置为NO后缓冲一定时间直接播放
    }
    //添加监听
    [self addObserve];
    
}

- (void)initAudioSession {
    AVAudioSession *audioSession = [AVAudioSession sharedInstance];
    NSError * error;
    BOOL success = [audioSession setCategory:AVAudioSessionCategoryPlayback error:&error];
    if(!success)
    {
        NSLog(@"error doing outputaudioportoverride - %@", [error localizedDescription]);
    }
}

//支持倍速切换必须调用
- (void)enableAudioTracks:(BOOL)enable inPlayerItem:(AVPlayerItem*)playerItem
{
    for (AVPlayerItemTrack *track in playerItem.tracks)
    {
        if ([track.assetTrack.mediaType isEqual:AVMediaTypeAudio])
        {
            track.enabled = enable;
        }
    }
}

#pragma mark - Observe
- (void)addObserve {
    //添加通知，拔出耳机后暂停播放
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(routeChange:) name:AVAudioSessionRouteChangeNotification object:nil];
    //监听播放器状态
    [self.playerItem addObserver:self forKeyPath:@"status" options:NSKeyValueObservingOptionNew context:nil];
    //除了播放器状态,还可以监听缓冲状态:无缓冲playbackBufferEmpty,缓冲足够可以播放:playbackBufferEmpty等,具体状态可以百度查找
    [self.playerItem addObserver:self forKeyPath:@"loadedTimeRanges" options:NSKeyValueObservingOptionNew context:nil];
    //播放完毕监听
    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(playDidEnd) name:AVPlayerItemDidPlayToEndTimeNotification object:self.playerItem];
}

- (void)addTimeObserve{
    __weak typeof(self) weakSelf = self;
    if (self.player) {
        if (self.timeObserve) {
            @try {
                [self.player removeTimeObserver:self.timeObserve];
                self.timeObserve = nil;
            }@catch(id anException) {
                NSLog(@"PlayanException=%@",anException);
            }
        }
        
        CMTime interval = CMTimeMakeWithSeconds(0.1, 100);
        self.timeObserve = [self.player addPeriodicTimeObserverForInterval:interval queue:nil usingBlock:^(CMTime time){
            AVPlayerItem *currentItem = weakSelf.playerItem;
            //进度时间
            CGFloat currentTime = (CGFloat)CMTimeGetSeconds([currentItem currentTime]);
            weakSelf.currentTime = currentTime;
            //状态
            AVPlayerItemStatus status = weakSelf.playerItem.status;
            if (status==AVPlayerItemStatusReadyToPlay) {
                
                weakSelf.state = SCAudioMediaStatePlaying;
                
            } else if (status == AVPlayerStatusFailed) {
                NSLog(@"AVPlayerItemStatusFailed");
                NSLog(@"%@",weakSelf.playerItem.error);
                weakSelf.state = SCAudioMediaStateFail;
                //发生错误，播放结束
                [weakSelf stop];
            }
            
        }];
    }
}

- (void)observeValueForKeyPath:(NSString *)keyPath ofObject:(id)object change:(NSDictionary<NSKeyValueChangeKey,id> *)change context:(void *)context {
    
    if ([keyPath isEqualToString:@"status"]) {
        AVPlayerItemStatus status = self.playerItem.status;
        if (status==AVPlayerItemStatusUnknown) {
            self.state = SCAudioMediaStateUnknow;
            NSLog(@"AVPlayerItemStatusUnknown");
        } else if (status == AVPlayerStatusFailed) {
            NSLog(@"AVPlayerItemStatusFailed");
            NSLog(@"%@",self.playerItem.error);
            
            if (self.bufferState != SCAudioMediaStateBufferEnd) {
                self.bufferState = SCAudioMediaStateBufferUnknow;
            }
            
            self.state = SCAudioMediaStateFail;
            //发生错误，播放结束
            [self stop];
        }
    }
    
    if ([keyPath isEqualToString:@"loadedTimeRanges"]) {
        if(self.bufferState == SCAudioMediaStateBufferEnd) { //缓冲已完成
            return;
        }
        AVPlayerItem * item = object;
        NSArray * array = item.loadedTimeRanges;
        //本次缓冲的时间范围
        CMTimeRange timeRange = [array.firstObject CMTimeRangeValue];
        //缓冲总长度
        NSTimeInterval totalBuffer = CMTimeGetSeconds(timeRange.start) + CMTimeGetSeconds(timeRange.duration);
        self.bufferTime = totalBuffer;
        CGFloat totalTime = (CGFloat)item.duration.value / item.duration.timescale;
        self.totalTime = totalTime;
        //缓冲的状态判断
        if (self.bufferTime == self.totalTime && self.bufferTime > 1) {
            self.bufferState = SCAudioMediaStateBufferEnd;
        } else {
            self.bufferState = SCAudioMediaStateBuffering;
        }
    }
}

- (void)removeTimeObserve{
    if (self.timeObserve) {
        [self.player removeTimeObserver:self.timeObserve];
        self.timeObserve = nil;
    }
}

- (void)playDidEnd {
    self.state = SCAudioMediaStateEnd;
    [self stop];
}

#pragma mark - 销毁
- (void)dealloc {
    [self.player pause];
    [self removeTimeObserve];
    [self.player.currentItem cancelPendingSeeks];
    [self.player.currentItem.asset cancelLoading];
    [self.playerItem removeObserver:self forKeyPath:@"status"];
    [self.playerItem removeObserver:self forKeyPath:@"loadedTimeRanges"];
    self.playerItem = nil;
    [self.player replaceCurrentItemWithPlayerItem:nil];
    self.player = nil;
    [[NSNotificationCenter defaultCenter] removeObserver:self];
    NSLog(@"player销毁");
}

#pragma mark - Public
- (void)seekTime:(NSInteger)time {
    [self.player seekToTime:CMTimeMake(time, 1) toleranceBefore:CMTimeMake(1, 1000) toleranceAfter:CMTimeMake(1, 1000) completionHandler:^(BOOL finished) {
        [self play];
    }];
}

- (void)play {
    [self initAudioSession];
    [self addTimeObserve];
    
    [self.player play];
    self.player.rate = self.rateValue;
}

- (void)pause {
    [self.player pause];
    [self removeTimeObserve];
    self.state = SCAudioMediaStatePause;
}

- (void)stop {
    [self.player pause];
    [self removeTimeObserve];
    [self.player seekToTime:CMTimeMake(0, 1)];
}

- (void)setState:(SCAudioMediaState)state {
    
    if(self.state == state && self.state != SCAudioMediaStatePlaying) {
        //非播放状态重复传值时，return;
        return;
    }
    
    _state = state;
    //block返回state的值
    if (self.scAudioUpdateTimeCallBack) {
        self.scAudioUpdateTimeCallBack(self.state, self.currentTime, self.totalTime);
    }
}

- (void)setBufferState:(SCAudioMediaBufferState)bufferState {
    _bufferState = bufferState;
    //block返回state的值
    if (self.scAudioBufferCallBack) {
        self.scAudioBufferCallBack(self.bufferState, self.bufferTime, self.totalTime);
    }
}

#pragma mark - 耳机监听
-(void)routeChange:(NSNotification *)notification{
    NSDictionary *dic=notification.userInfo;
    int changeReason= [dic[AVAudioSessionRouteChangeReasonKey] intValue];
    //等于AVAudioSessionRouteChangeReasonOldDeviceUnavailable表示旧输出不可用
    if (changeReason==AVAudioSessionRouteChangeReasonOldDeviceUnavailable) {
        [self pause];
    }
}

@end
